package gouhuo.allbugs.top.common;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import com.google.gson.Gson;
import gouhuo.allbugs.top.config.HttpSessionConfigurator;
import gouhuo.allbugs.top.model.enums.ChatEnum;
import gouhuo.allbugs.top.model.vo.ChatVO;
import gouhuo.allbugs.top.service.ChatService;
import gouhuo.allbugs.top.service.TeamService;
import gouhuo.allbugs.top.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * WebSocket消息类
 */
@Component
@Slf4j
@ServerEndpoint(value = "/websocket/{userId}/{teamId}", configurator = HttpSessionConfigurator.class)
public class WebSocket {

    /**
     * 保存队伍的连接信息
     */
    private static final Map<String, ConcurrentHashMap<String, WebSocket>> ROOMS = new HashMap<>();

    /**
     * 线程安全的无序的集合
     */
    private static final CopyOnWriteArraySet<Session> SESSIONS = new CopyOnWriteArraySet<>();

    /**
     * 存储在线连接数
     */
    private static final Map<String, Session> SESSION_POOL = new HashMap<>(0);
    private static ChatService chatService;

    /**
     * 房间在线人数
     */
    private static int onlineCount = 0;

    /**
     * 当前信息
     */
    private Session session;
    private HttpSession httpSession;

    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        WebSocket.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        WebSocket.onlineCount--;
    }

    @Resource
    public void setHeatMapService(ChatService chatService) {
        WebSocket.chatService = chatService;
    }

    @OnOpen
    public void onOpen(Session session, @PathParam(value = "userId") String userId, @PathParam(value = "teamId") String teamId, EndpointConfig config) {
        try {
            if (StrUtil.isBlank(userId) || "undefined".equals(userId)) {
                sendError(userId, "参数有误");
                return;
            }
            HttpSession httpSession = (HttpSession) config.getUserProperties().get(HttpSession.class.getName());
            this.session = session;
            this.httpSession = httpSession;
            if ("undefined".equals(teamId)) {
                SESSIONS.add(session);
                SESSION_POOL.put(userId, session);
//                log.info("有新用户加入，userId={}, 当前在线人数为：{}", userId, SESSION_POOL.size());
//                sendAllUsers();
            } else {
                if (!ROOMS.containsKey(teamId)) {
                    ConcurrentHashMap<String, WebSocket> room = new ConcurrentHashMap<>(0);
                    room.put(userId, this);
                    ROOMS.put(teamId, room);
                } else {
                    if (!ROOMS.get(teamId).containsKey(userId)) {
                        ROOMS.get(teamId).put(userId, this);
                    }
                }
                addOnlineCount();
//                log.info("有新连接加入！当前房间在线人数为" + getOnlineCount());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @OnClose
    public void onClose(@PathParam("userId") String userId, @PathParam(value = "teamId") String teamId, Session session) {
        try {
            if ("undefined".equals(teamId)) {
                if (!SESSION_POOL.isEmpty()) {
                    SESSION_POOL.remove(userId);
                    SESSIONS.remove(session);
                }
//                log.info("【WebSocket消息】连接断开，总数为：" + SESSION_POOL.size());
//                sendAllUsers();
            } else {
                ROOMS.get(teamId).remove(userId);
                if (getOnlineCount() > 0) {
                    subOnlineCount();
                }
//                log.info("用户退出:当前房间在线人数为:" + getOnlineCount());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @OnMessage
    public void onMessage(String message, @PathParam("userId") String userId, @PathParam("teamId") String teamId) {
        if ("PING".equals(message)) {
            sendOneMessage(userId, "pong");
//            log.error("心跳包，发送给{},在线:{}人", userId, getOnlineCount());
            return;
        }
//        log.info("服务端收到用户userId={}的消息:{}", userId, message);
        ChatVO chatVO = new Gson().fromJson(message, ChatVO.class);
        Long fromId = chatVO.getFromId();
        String text = chatVO.getText();
        Integer scope = chatVO.getScope();
        ChatEnum chatEnum = ChatEnum.getEnumByValue(scope);
        if (ChatEnum.PRIVATE_CHAT.equals(chatEnum)) {
            // 私聊
            Long toId = chatVO.getToId();
            chatService.saveChatToRedis(message, fromId, toId, null);
            privateChat(message, fromId, toId, text);
        } else if (ChatEnum.TEAM_CHAT.equals(chatEnum)) {
            // 队伍内聊天
            Long teamIdLong = Long.valueOf(teamId);
            chatService.saveChatToRedis(message, null, null, teamIdLong);
            teamChat(message, fromId, teamIdLong, text);
        }
//        else {
//            hallChat(fromUser, text, chatType);
//        }
    }

    /**
     * 群聊
     *
     * @param message
     * @param fromId
     * @param teamId
     * @param text
     */
    private void teamChat(String message, Long fromId, Long teamId, String text) {
        try {
            ConcurrentHashMap<String, WebSocket> map = ROOMS.get(String.valueOf(teamId));
            // keySet获取map集合key的集合  然后在遍历key即可
            for (String key : map.keySet()) {
                try {
                    map.get(key).session.getBasicRemote().sendText(message);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
//            log.error("队伍聊天，发送者={},队伍={},内容={},在线:{}人", fromId, teamId, text, getOnlineCount());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 私聊
     *
     * @param text
     */
    private void privateChat(String message, Long fromId, Long toId, String text) {
        String toIdStr = toId.toString();
        Session toSession = SESSION_POOL.get(toIdStr);
        if (toSession != null) {
            sendOneMessage(toIdStr, message);
//            log.info("userId={}发送给用户userId={}，消息：{}", fromId, toId, text);
        } else {
//            log.info("发送失败，未找到用户userId={}的session", toId);
        }
    }

    //
//    /**
//     * 大厅聊天
//     *
//     * @param user
//     * @param text
//     */
//    private void hallChat(User user, String text, Integer chatType) {
//        savaChat(user.getId(), null, text, null, chatType);
//        ChatVO ChatVO = new ChatVO();
//        WebSocketVo fromWebSocketVo = new WebSocketVo();
//        BeanUtils.copyProperties(user, fromWebSocketVo);
//        ChatVO.setFormUser(fromWebSocketVo);
//        ChatVO.settext(text);
//        ChatVO.setChatType(chatType);
//        ChatVO.setCreateTime(DateUtil.format(new Date(), "yyyy年MM月dd日 HH:mm:ss"));
//        if (user.getUserRole() == ADMIN_ROLE) {
//            ChatVO.setIsAdmin(true);
//        }
//        User loginUser = (User) this.httpSession.getAttribute(LOGIN_USER_STATUS);
//        if (loginUser.getId() == user.getId()) {
//            ChatVO.setIsMy(true);
//        }
//        String toJson = new Gson().toJson(ChatVO);
//        sendAllMessage(toJson);
//        chatService.deleteKey(CACHE_CHAT_HALL, String.valueOf(user.getId()));
//    }
//

    /**
     * 发送失败
     *
     * @param userId
     * @param errorMessage
     */
    private void sendError(String userId, String errorMessage) {
        JSONObject obj = new JSONObject();
        obj.set("error", errorMessage);
        sendOneMessage(userId, obj.toString());
    }

    /**
     * 此为单点消息
     *
     * @param userId  用户编号
     * @param message 消息
     */
    public void sendOneMessage(String userId, String message) {
        Session session = SESSION_POOL.get(userId);
        if (session != null && session.isOpen()) {
            try {
                synchronized (session) {
                    log.info("【WebSocket消息】单点消息：" + message);
                    session.getAsyncRemote().sendText(message);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

//    /**
//     * 发送所有在线用户信息
//     */
//    public void sendAllUsers() {
//        log.info("【WebSocket消息】发送所有在线用户信息");
//        HashMap<String, List<WebSocketVo>> stringListHashMap = new HashMap<>(0);
//        List<WebSocketVo> webSocketVos = new ArrayList<>();
//        stringListHashMap.put("users", webSocketVos);
//        for (Serializable key : SESSION_POOL.keySet()) {
//            User user = userService.getById(key);
//            WebSocketVo webSocketVo = new WebSocketVo();
//            BeanUtils.copyProperties(user, webSocketVo);
//            webSocketVos.add(webSocketVo);
//        }
//        sendAllMessage(JSONUtil.toJsonStr(stringListHashMap));
//    }
//
//    /**
//     * 此为广播消息
//     *
//     * @param message 消息
//     */
//    public void sendAllMessage(String message) {
//        log.info("【WebSocket消息】广播消息：" + message);
//        for (Session session : SESSIONS) {
//            try {
//                if (session.isOpen()) {
//                    synchronized (session) {
//                        session.getBasicRemote().sendText(message);
//                    }
//                }
//            } catch (Exception e) {
//                e.printStackTrace();
//            }
//        }
//    }

}
